/*
 * Copyright (c) 1997, 1998, 2003, 2006 Aleksandar Samardzic
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "color.h"
#include "defs.h"		/* for Min() macro */

/* Color_RGBtoHSV - convert color from RGB to HSV representation */
void
Color_RGBtoHSV(rgb, hsv)
     PColor          rgb;	/* RGB color */
     PColor          hsv;	/* HSV color */
{
	double          min,
	                max;
	double          delta;

	/* find HSV value */
	min = Min(Min(rgb[RED], rgb[GREEN]), rgb[BLUE]);
	max = Max(Max(rgb[RED], rgb[GREEN]), rgb[BLUE]);
	hsv[VALUE] = max;

	/* find HSV saturation */
	hsv[SATURATION] = (max != 0) ? (max - min) / max : 0;

	/* find HSV hue */
	if (hsv[SATURATION] == 0)
		hsv[HUE] = UNDEFINED;
	else {
		delta = max - min;
		if (rgb[RED] == max)
			hsv[HUE] = (rgb[GREEN] - rgb[BLUE]) / delta;
		else if (rgb[GREEN] == max)
			hsv[HUE] = 2 + (rgb[BLUE] - rgb[RED]) / delta;
		else if (rgb[BLUE] == max)
			hsv[HUE] = 4 + (rgb[RED] - rgb[GREEN]) / delta;

		/* convert hue to degrees */
		hsv[HUE] *= 60;
		if (hsv[HUE] < 0)
			hsv[HUE] += 360;
	}
}

/* Color_HSVtoRGB - convert color from HSV to RGB representation */
void
Color_HSVtoRGB(hsv, rgb)
     PColor          hsv;	/* HSV color */
     PColor          rgb;	/* RGB color */
{
	int             i;
	double          f,
	                p,
	                q,
	                t;

	if (hsv[SATURATION] == 0) {
		/* achromatic color: there is no hue */
		if (hsv[HUE] == UNDEFINED)
			rgb[RED] = rgb[GREEN] = rgb[BLUE] = hsv[VALUE];
		/* else error */
	} else {
		/* convert hue to [1,6] range */
		if (hsv[HUE] == 360)
			hsv[HUE] = 0;
		hsv[HUE] /= 60;
		i = (int) (hsv[HUE]);

		/* find R, G and B components */
		f = hsv[HUE] - i;
		p = hsv[VALUE] * (1 - hsv[SATURATION]);
		q = hsv[VALUE] * (1 - hsv[SATURATION] * f);
		t = hsv[VALUE] * (1 - hsv[SATURATION] * (1 - f));
		switch (i) {
		case 0:
			rgb[RED] = hsv[VALUE];
			rgb[GREEN] = t;
			rgb[BLUE] = p;
			break;

		case 1:
			rgb[RED] = q;
			rgb[GREEN] = hsv[VALUE];
			rgb[BLUE] = p;
			break;

		case 2:
			rgb[RED] = p;
			rgb[GREEN] = hsv[VALUE];
			rgb[BLUE] = t;
			break;

		case 3:
			rgb[RED] = p;
			rgb[GREEN] = q;
			rgb[BLUE] = hsv[VALUE];
			break;

		case 4:
			rgb[RED] = t;
			rgb[GREEN] = p;
			rgb[BLUE] = hsv[VALUE];
			break;

		case 5:
			rgb[RED] = hsv[VALUE];
			rgb[GREEN] = p;
			rgb[BLUE] = q;
			break;
		}
	}
}
